package com.bizfx.component.views
{
	import com.bizfx.collections.HashMap;
	import com.bizfx.collections.IMap;
	import com.bizfx.component.controls.CommandBar;
	import com.bizfx.component.controls.ICommandBar;
	import com.bizfx.component.fields.IField;
	import com.bizfx.component.fields.IInitableField;
	import com.bizfx.component.fields.IValidationField;
	import com.bizfx.events.CommandRaiseEvent;
	import com.bizfx.events.ViewCommandEvent;
	import com.bizfx.events.ViewValidationResultEvent;
	import com.bizfx.utils.ListUtils;
	import com.bizfx.utils.ObjectUtils;
	import com.bizfx.utils.StringUtils;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	
	import mx.collections.ArrayCollection;
	import mx.collections.IList;
	import mx.containers.Box;
	import mx.containers.VBox;
	import mx.core.Container;
	import mx.core.UIComponent;
	import mx.events.ChildExistenceChangedEvent;
	import mx.events.ValidationResultEvent;
	
	[Style(name="commandsHorizontalAlign", type="String", enumeration="left,center,right", inherit="no", defaultValue="left")]
	
	[Style(name="commandsPosition", type="String", enumeration="top,bottom", inherit="no", defaultValue="top")]
	
	[Style(name="commandsIndex", type="Number", inherit="no", defalut)]
	
	public class BaseDetailView extends BaseView implements IDetailView {
		
		/**
		 * 此状态说明视图正处于浏览状态，所有的Field都不能被编辑，只能查看。
		 */
		public static var DetailViewStatus_View:String = "view";
		/**
		 * 此状态说明视图正处于新增状态，此时的视图数据为新对象，不包含任何属性。
		 */
		public static var DetailViewStatus_New:String = "new";
		/**
		 * 此状态说明视图正处于编辑状态，此时的视图数据是通过远程读取的实体数据对象。
		 */
		public static var DetailViewStatus_Edit:String = "edit";
		
		private var fieldsMap:HashMap = new HashMap();
		
		protected var commandBar:ICommandBar;
		
		private var container:VBox;
		
		private var detailContainer:Box;
		
		private var commandBarContainer:Box;
		
		private var readOnlyDirty:Boolean = true;
		
		private var validatedFields:ArrayCollection = new ArrayCollection();
		
		private var needValidatedFields:ArrayCollection = new ArrayCollection();
		
		private var validFields:ArrayCollection = new ArrayCollection();
		
		private var invalidFields:IMap = new HashMap();
		
		public function BaseDetailView():void {
			super();
			this.addEventListener(ChildExistenceChangedEvent.CHILD_ADD, childAddEventHandler);
			this.addEventListener(ChildExistenceChangedEvent.CHILD_REMOVE, childRemoveEventHandler);
		}
		
		private var formContainerDirty:Boolean = false;
		
		private var commandsHorizontalAlignDirty:Boolean = true;
		
		private var commandsPositionDirty:Boolean = false;
		
		private var _formContainer:Container;
		[Bindable("formContainerChanged")]
		public function get formContainer():Container {
			return _formContainer;
		}
		
		public function set formContainer(value:Container):void {
			if (_formContainer != value) {
				this.formContainerDirty = true;
				_formContainer = value;
				this.dispatchEvent(new Event("formContainerChanged"));
				this.invalidateProperties();
				this.invalidateDisplayList();
			}
		}
		
		private var _readOnly:Boolean;
		[Bindable]
		public function get readOnly():Boolean
		{
			return _readOnly;
		}

		override public function set readOnly(value:Boolean):void {
			if (readOnly != value) {
				this.readOnlyDirty = true;
				this.invalidateProperties();
			}
		}
		
		private var _initData:Object;
		
		[Bindable("initDataChanged")]
		public function get initData():Object
		{
			return _initData;
		}
		
		public function set initData(value:Object):void {
			if (_initData != value) {
				_initData = value;
				this.dispatchEvent(new Event("initDataChanged"));	
			}
			this.bindInitViewDataToForm();
		}
		
		private var _needInit:Boolean = false;
		[Bindable]
		public function get needInit():Boolean
		{
			return _needInit;
		}
		
		public function set needInit(value:Boolean):void
		{ 
			_needInit = value;
		}
		
		private var fields:IList = new ArrayCollection();
		/**
		 * 获取视图的所有字段
		 */
		public function getFields():IList {
			fields.removeAll();
			for (var i:int; i < this.fieldsMap.size(); i++) {
				fields.addItem(fieldsMap.values()[i]);
			}
			return fields;
		}

		/**
		 * 通过键值获取字段
		 */
		public function getFieldByKey(fieldKey:String):IField {
			if (this.fieldsMap.containsKey(fieldKey))
				return IField(this.fieldsMap.get(fieldKey));
			return null;
		}
		
		/**
		 * 添加字段
		 */
		public function registerField(field:IField):void {
			if (field) {
				if (!this.fieldsMap.containsKey(field.fieldKey)) {
					this.fieldsMap.put(field.fieldKey, field);
					if (field is IValidationField) {
						this.needValidatedFields.addItem(field);
						field.addEventListener(ValidationResultEvent.VALID, validationResultEventHandler);
						field.addEventListener(ValidationResultEvent.INVALID, validationResultEventHandler);
					}
					field.readOnly = this.readOnly;
					field.data = ObjectUtils.getPropertyValue(this._viewDataSource, field.bindProperty);
				}	
			}
		}
		
		/**
		 * 删除字段
		 */
		public function unregisterFieldByKey(fieldKey:String):void {
			if (this.fieldsMap.containsKey(fieldKey)) {
				this.fieldsMap.remove(fieldKey);
			}
		}
		
		/**
		 * 验证视图
		 */
		public function validate():void {
			this.validFields = new ArrayCollection();
			this.invalidFields = new HashMap();
			this.validatedFields = new ArrayCollection();

			for each(var field:IField in this.needValidatedFields) {
				IValidationField(field).validate();
			}
		}
		
		override protected function createChildren():void {
			super.createChildren();

			this.createContainers();
			
			this.createCommandBar();
		}
		
		override protected function childrenCreated():void {
			if (this.getStyle("commandsHorizontalAlign") == undefined) {
				this.setStyle("commandsHorizontalAlign", "left");
			}
			
			if (this.getStyle("commandsPosition") == undefined) {
				this.setStyle("commandsPosition", "top");
			}
			super.childrenCreated();
		}
		
		protected function createContainers():void {
			this.container = new VBox();
			this.container.percentHeight = 100;
			this.container.percentWidth = 100;
			this.addChild(container);
			
			this.detailContainer = new Box();
			this.detailContainer.percentHeight = 100;
			this.detailContainer.percentWidth = 100;
			this.container.addChild(this.detailContainer);
			
			if (!this.commandBarContainer) {
				this.commandBarContainer = new Box();
				this.commandBarContainer.percentWidth = 100;
				
				var commandsPositionStyle:String = this.getStyle("commandsPosition");
				var i:int = 0;
				if (commandsPositionStyle == "bottom") {
					i = this.container.getChildren().length;
				}
				this.container.addChildAt(this.commandBarContainer, i);
			}
		}
		
		protected function createCommandBar():void {
			if (this.commandBarContainer && !this.commandBar) {
				this.commandBar = new CommandBar();
				this.commandBar.commands = this.commands;
				UIComponent(this.commandBar).percentWidth = 100;
				this.commandBarContainer.visible = this.commands.length > 0;
				this.commandBarContainer.includeInLayout = this.commands.length > 0;
				this.commandBar.addEventListener(CommandRaiseEvent.Command_Raise, commandBarCommandRaiseHandler);
				this.commandBarContainer.addChild(DisplayObject(this.commandBar));
			}
		}
		
		override public function styleChanged(styleProp:String):void {
			super.styleChanged(styleProp);
			switch(styleProp) {  
				case "commandsHorizontalAlign":
					this.commandsHorizontalAlignDirty = true;
					this.invalidateDisplayList();
					break;
				case "commandsPosition":
					this.commandsPositionDirty = true;
					this.invalidateDisplayList();
					break;
			}
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			//formContainer更改后的处理
			if (this.formContainerDirty) {
				this.formContainerDirty = false;
				if (this.detailContainer && this._formContainer) {
					if (!this.detailContainer.contains(this._formContainer)) {
						this.detailContainer.addChild(this._formContainer);
					}
				}
			}
			
			if (this.readOnlyDirty) {
				this.readOnlyDirty = false;
				var fields:IList = this.getFields();
				for (var i:int; i < fields.length; i++) {
					var field:IField = fields.getItemAt(i) as IField;
					field.readOnly = this.readOnly;
				}
			}
			
			if (this.commandsHorizontalAlignDirty) {
				this.commandsHorizontalAlignDirty = false;
				UIComponent(this.commandBar).setStyle("horizontalAlign", this.getStyle("commandsHorizontalAlign"));
			}
			
			if (this.commandsDirty) {
				this.commandsDirty = false;
				this.commandBar.commands = this.commands;
				this.commandBarContainer.visible = this.commands.length > 0;
				this.commandBarContainer.includeInLayout = this.commands.length > 0;
			}
			
			if (this.commandsPositionDirty) {
				this.commandsPositionDirty = false;
				var commandsPositionStyle:String = this.getStyle("commandsPosition");
				if (this.container.contains(this.commandBarContainer)) {
					this.container.removeChild(this.commandBarContainer);
				}
				if (commandsPositionStyle == "bottom") {
					this.container.addChildAt(this.commandBarContainer, container.getChildren().length);
				} else if (commandsPositionStyle == "top"){
					this.container.addChildAt(this.commandBarContainer, 0);
				} else {
					this.container.addChildAt(this.commandBarContainer, 0);
				}
			}
		}
		
		public function hideAllViewCommands():void {
			this.commandBar.hideAllCommands();
		}
		
		public function showViewCommand(commandKey:String):void {
			this.commandBar.showCommandByKey(commandKey);
		}
		
		override public function bindViewDataToForm():void {
			if (this._viewDataSource != null) {
				var fields:IList = this.getFields();
				for (var i:int; i < fields.length; i++) {
					var field:IField = fields.getItemAt(i) as IField;
					field.data = ObjectUtils.getPropertyValue(this._viewDataSource, field.bindProperty);
				}
			}
		}
		
		override protected function retrieveViewDataFromForm():void {
			if (this._viewDataSource == null) {
				this._viewDataSource = new ObjectProxy(new Object());
			}
			var fields:IList = this.getFields();
			for (var i:int; i < fields.length; i++) {
				var field:IField = fields.getItemAt(i) as IField;
				ObjectUtils.setPropertyValue(this._viewDataSource, field.bindProperty, field.data);
			}
		}
		
		override public function bindInitViewDataToForm():void {
			if (this.initData != null) {
				var fields:IList = this.getFields();
				for (var i:int; i < fields.length; i++) {
					var field:IField = fields.getItemAt(i) as IField;
					if (field is IInitableField && (field as IInitableField).needInit) {
						(field as IInitableField).dataProvider = ObjectUtils.getPropertyValue(this.initData, (field as IInitableField).initDataBindProperty);
					}
				}
			}
		}
				
		/**
		 * Event Handlers
		 */
		
		private function commandBarCommandRaiseHandler(event:CommandRaiseEvent):void {
			this.dispatchEvent(new ViewCommandEvent(ViewCommandEvent.ViewCommand_Raise, event.viewCommand));
		}
		
		private function validationResultEventHandler(event:Event):void {
			if (event is ValidationResultEvent) {
				var sender:IField = IField(event.target);
				if (!this.validatedFields.contains(sender.fieldKey)) {
					this.validatedFields.addItem(sender.fieldKey);
				}
				if (event.type == ValidationResultEvent.VALID) {
					this.validFields.addItem(sender.fieldKey);
				} else if (event.type == ValidationResultEvent.INVALID) {
					this.invalidFields.put(sender.fieldKey, event);
				}
				if (this.needValidatedFields.length == this.validatedFields.length) {
					if (this.invalidFields.size() > 0) {
						var results:IList = new ArrayCollection();
						for each(var re:ValidationResultEvent in this.invalidFields.values()) {
							ListUtils.appendFromArray(results, re.results);
						}
						this.dispatchEvent(new ViewValidationResultEvent(ViewValidationResultEvent.INVALID, true, false, results));
					} else {
						this.dispatchEvent(new ViewValidationResultEvent(ViewValidationResultEvent.VALID, true));
					}
				}	
			}
		}
		
		private function childAddEventHandler(event:ChildExistenceChangedEvent):void {
			if (event.relatedObject is IField) {
				var field:IField = event.relatedObject as IField;
				if (StringUtils.isNullOrEmpty(field.fieldKey)) {
					field.fieldKey = UIDUtil.createUID();
				}
				this.registerField(field);
			} else if (event.relatedObject is Container) {
				var container:Container = event.relatedObject as Container;
				this.registerChildFields(container);
			}
		}
		
		private function childRemoveEventHandler(event:ChildExistenceChangedEvent):void {
			if (event.relatedObject is IField) {
				var field:IField = event.relatedObject as IField;
				this.unregisterFieldByKey(field.fieldKey);
			}
		}
		
		private function registerChildFields(container:Container):void {
			//注册容器子对象添加事件
			container.addEventListener(ChildExistenceChangedEvent.CHILD_ADD, childAddEventHandler);
			container.addEventListener(ChildExistenceChangedEvent.CHILD_REMOVE, childRemoveEventHandler);
			//获取容器当前Fields
			for each (var child:DisplayObject in container.getChildren()) {
				if(child is IField) {
					this.registerField(child as IField);
				} else if (child is Container) {
					this.registerChildFields(child as Container)
				}
			}
		}
	}
}